package com.jf.docsify.common.utils;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.RmCommand;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.internal.storage.file.WindowCache;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.storage.file.WindowCacheConfig;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jf.docsify.config.DocsifyConfig;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.JsonKit;

/**
 * Description: Git Server 工具类
 *
 * @author chenwr
 * @version 1.0
 *  https://gitee.com/search/translate?q=翻译成英文 翻译成英文
 * <pre>
 * 修改记录:
 * 修改后版本           修改人       修改日期         修改内容
 * 2022/7/28.1       chenwr    2022/7/28           Create
 * </pre>
 * @date 2022/7/28
 */
public class GitServerUtil {

    private static final Logger logger = LoggerFactory.getLogger(GitServerUtil.class);

    private GitServerUtil() {
    }

    /**
     * 初始化版本库
     * @param projectName 项目名称
     * @param enProjectName 项目名称（英文）
     * @param userName 用户名
     * @param group
     * @param gitBaseURL
     * @return filePath
     */
    public static String init(String projectName, String enProjectName, String userName, String password, String group, String gitBaseURL) {
        AssertUtil.hasText(projectName, "文档名称不能为空");
        AssertUtil.hasText(userName, "用户名不能为空");
        AssertUtil.hasText(group, "组织路径不能为空");
        boolean isException = false;
        String contentFilePath;
        String gitUrl;
        if (StringUtils.isBlank(enProjectName)) {
            Map<String, String> queryParams = new HashMap<>();
            queryParams.put("q", projectName);
            String jsonStr = HttpKit.get("https://gitee.com/search/translate", queryParams);
            Map<String, String> res = JsonKit.parse(jsonStr, Map.class);
            enProjectName = res.get("result");
        }
        AssertUtil.hasText(enProjectName, "英文名称不能为空");
        String gitFolderName = enProjectName + ".git";
        String gitFilePath = DocsifyConfig.defaultPath + File.separator + DocsifyConfig.gitDefaultFolderName + File.separator + group + File.separator + gitFolderName;
        FileUtil.mkdirs(gitFilePath);
        File gitDir = new File(gitFilePath);
        contentFilePath = DocsifyConfig.defaultPath + File.separator + DocsifyConfig.gitDefaultFolderName + File.separator + group + File.separator + enProjectName;
        gitUrl = gitBaseURL + "/" + group + "/" + gitFolderName;
        Repository build = null;
        Git git = null;
        try {
            git = Git.init().setBare(true).setGitDir(gitDir).setDirectory(gitDir).call();
            build = new RepositoryBuilder().setGitDir(gitDir).setMustExist(true).build();
            build.getConfig().setString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_NAME, userName);
            build.getConfig().save();
        } catch (Exception e) {
            isException = true;
            e.printStackTrace();
        } finally {
            if (build != null) {
                build.close();
            }
            if (git != null) {
                git.close();
            }
            if (!isException && StringUtils.isNotBlank(contentFilePath)) {
                cloneRepository(contentFilePath, gitUrl, userName, password);
            }
        }
        return gitFilePath;
    }

    public static void cloneRepository(String path, String gitUrl, String userName, String password) {
        Git git = null;
        try {
            File filePath = new File(path);
            CloneCommand clone = Git.cloneRepository();
            clone.setBare(false);
            clone.setCloneAllBranches(true);
            clone.setDirectory(filePath).setURI(gitUrl);
            UsernamePasswordCredentialsProvider user = new UsernamePasswordCredentialsProvider(userName, password);
            clone.setCredentialsProvider(user);
            git = clone.call();
            git.close();

            generatorDefaultMdFile(path);

            // 提交操作
            git = Git.open(filePath);

            AddCommand addCommand = git.add();
            addCommand.addFilepattern(".").call();
            Status status = git.status().call();
            int add = status.getAdded().size();
            logger.info("新增{}个文件", add);

            int chang = status.getChanged().size();
            logger.info("变更{}个文件", chang);

            int remove = status.getRemoved().size();
            logger.info("移除{}个文件", remove);

            int miss = status.getMissing().size();
            logger.info("缺失{}个文件", miss);

            int modified = status.getModified().size();
            logger.info("修改{}个文件", modified);

            int conflicting = status.getConflicting().size();
            logger.info("有{}个冲突", conflicting);

            int ignored = status.getIgnoredNotInIndex().size();
            logger.info("忽略{}个文件", ignored);

            if (add == 0 && chang == 0 && remove == 0 && miss == 0 && modified == 0 && conflicting == 0 && ignored == 0) {
                logger.info("文件没有任何变动");
            }

            RmCommand rm = git.rm();

            // 循环add missing 的文件 没研究出missing和remove的区别 就是删除的文件也要提交到git
            Set<String> missing = status.getMissing();
            for(String m : missing) {

                rm.addFilepattern(m).call();

                // 需重新获取rm不然会报错
                rm = git.rm();

                // 需重新获取status不然会报错
                status = git.status().call();
            }

            // 循环add remove 的文件
            Set<String> removed = status.getRemoved();
            for(String r : removed) {

                rm.addFilepattern(r).call();

                // 需重新获取rm不然会报错
                rm = git.rm();

                // 需重新获取status不然会报错
                status = git.status().call();
            }

            // 提交
            git.commit().setMessage("初始化").call();    // 这里可以自己定义commit的消息
            logger.info("commit成功，commit的消息是{}", "初始化");

            // 推送
            git.push().setCredentialsProvider(user).call();
            logger.info("push成功");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }

    private static void generatorDefaultMdFile(String filePath) {
        FileUtil.writeFile(filePath + File.separator + "README.md", "# README");
        FileUtil.writeFile(filePath + File.separator + "_coverpage.md", "# README");
        FileUtil.writeFile(filePath + File.separator + "_navbar.md", "# README");
        FileUtil.writeFile(filePath + File.separator + "_sidebar.md", "# README");
    }

    public static void pullMaster(String path, String userName, String password) {
        Git git = null;
        try {
            File filePath = new File(path);
            CredentialsProvider user = new UsernamePasswordCredentialsProvider(userName, password);
            git = Git.open(filePath);
            git.checkout().setName("master").call();
            git.fetch().setCredentialsProvider(user).call();
            git.pull().setCredentialsProvider(user).call();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (git != null) {
                git.close();
            }
        }
    }

    public static void reConfigWindowCache() {
        boolean isWin = SystemUtil.isWin();
        if (isWin) {
            WindowCacheConfig windowCacheConfig = new WindowCacheConfig();
            windowCacheConfig.setPackedGitMMAP(false);
            windowCacheConfig.install();
        }
    }
}